﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using Dashboard.ClusteringSvc;
using UI.Dendrogram;
using UI.NetworkDiagram;

namespace Dashboard
{
    public partial class ClusterResultView : UserControl
    {
        private DocumentClusteringOutput _Output;

        public ClusterResultView()
        {
            InitializeComponent();
            this.termGrid.SwitchToClusterTopView += new OnSwitchToClusterTopView(termGrid_SwitchToClusterTopView);
            this.clusterNetwork.NetworkNodeSelected += new OnNetworkNodeSelected(clusterNetwork_NetworkNodeSelected);
        }

        void termGrid_SwitchToClusterTopView()
        {
            if(this._Output !=null)
            {
                this.clusterGrid.LoadClusterResult(this._Output);
                this.termGrid.LoadTermGridResult(this._Output);
                this.LoadClusterNetwork(this._Output);
            }
        }

        public void LoadClusterResult(DocumentClusteringOutput output)
        {
            this._Output = output;
            this.clusterGrid.LoadClusterResult(this._Output);
            this.termGrid.LoadTermGridResult(this._Output);
            this.LoadClusterNetwork(this._Output);
            this.clusterDendrogram.LoadClusterData(this._Output);
        }

        #region clusternode/docnode
        private Dictionary<int,ClusterNode> ToNetworkNodes(DocumentClusteringOutput output)
        {
            Dictionary<int,ClusterNode> clusterNodes=new Dictionary<int, ClusterNode>();
            foreach(int clusterID in output.ClusteredDocs.Keys)
            {
                double diameter = output.ClusterDiameters[clusterID];
                string label = output.ClusterLabels[clusterID];
                List<int> includedDocIDs = output.ClusteredDocs[clusterID].ToList();
                Dictionary<int,string> docTitles=new Dictionary<int, string>();
                Dictionary<int,Dictionary<int,double>> docDocDistances=new Dictionary<int, Dictionary<int, double>>();
                foreach(int docID in includedDocIDs)
                {
                    docTitles.Add(docID, output.DocTitles[docID]);
                    Dictionary<int,double> toDocDistances=new Dictionary<int, double>();
                    foreach(int docID2 in includedDocIDs)
                    {
                        if(docID2 !=docID)
                        {
                            double distance = 1;
                            if (output.DocDocDistances.ContainsKey(docID) &&
                                output.DocDocDistances[docID].ContainsKey(docID2))
                                distance = output.DocDocDistances[docID][docID2];
                            else if (output.DocDocDistances.ContainsKey(docID2) &&
                                output.DocDocDistances[docID2].ContainsKey(docID))
                                distance = output.DocDocDistances[docID2][docID];
                            toDocDistances.Add(docID2, distance);
                        }
                    }
                    docDocDistances.Add(docID, toDocDistances);
                }
                ClusterNode clusterNode = new ClusterNode();
                clusterNode.BindData(
                    clusterID, diameter, label, includedDocIDs, docTitles, docDocDistances);
                clusterNodes.Add(clusterID, clusterNode);
            }
            return clusterNodes;
        }
        #endregion

        #region network vertice/edges
        private void LoadClusterNetwork(DocumentClusteringOutput output)
        {
            Dictionary<int, Vertice> vertices;
            List<Edge> edges;
            this.GetNetworkBetweenClusters(output, out vertices, out edges);
            this.clusterNetwork.BindNetworkData(vertices.Values.ToList(),edges);
            this.clusterNetwork.StartSimulation();
        }
        
        void clusterNetwork_NetworkNodeSelected(string entityType, int entityID)
        {
            if (entityType == "cluster")
            {
                Dictionary<int, Vertice> vertices;
                List<Edge> edges;
                this.GetNetworkBetweenDocument(this._Output, entityID,
                    out vertices, out edges);
                this.clusterNetwork.BindNetworkData(vertices.Values.ToList(), edges);
                this.clusterNetwork.StartSimulation();

                this.termGrid.LoadTermGridResultForCluster(entityID);
            }
        }

        private void GetNetworkBetweenClusters(DocumentClusteringOutput output,
            out Dictionary<int, Vertice> vertices, out List<Edge> edges)
        {
            vertices=new Dictionary<int, Vertice>();
            edges=new List<Edge>();
            Dictionary<int,Dictionary<int,double>> clusterClusterDistances=
                new Dictionary<int, Dictionary<int, double>>();
            foreach(int clusterID1 in output.ClusteredDocs.Keys)
            {
                List<int> includedDocIDs1 = output.ClusteredDocs[clusterID1].ToList();
                Dictionary<int,double> toClusterDistances=new Dictionary<int, double>();
                foreach(int clusterID2 in output.ClusteredDocs.Keys)
                {
                    if(clusterID2 !=clusterID1)
                    {
                        List<int> includedDocIDs2 = output.ClusteredDocs[clusterID2].ToList();
                        double clusterDistance = double.PositiveInfinity;
                        foreach(int fromDocID in includedDocIDs1)
                        {
                            foreach(int toDocID in includedDocIDs2)
                            {
                                double docDistance = 1;
                                if (output.DocDocDistances.ContainsKey(fromDocID) &&
                                    output.DocDocDistances[fromDocID].ContainsKey(toDocID))
                                    docDistance = output.DocDocDistances[fromDocID][toDocID];
                                else if (output.DocDocDistances.ContainsKey(toDocID) &&
                                    output.DocDocDistances[toDocID].ContainsKey(fromDocID))
                                    docDistance = output.DocDocDistances[toDocID][fromDocID];
                                if(docDistance<clusterDistance)
                                    clusterDistance = docDistance;
                            }
                        }
                        toClusterDistances.Add(clusterID2, clusterDistance);
                    }
                }
                clusterClusterDistances.Add(clusterID1, toClusterDistances);
            }

            foreach(int clusterID in output.ClusteredDocs.Keys)
            {
                Vertice v = new Vertice(
                    clusterID,
                    "Cluster " + clusterID.ToString(),
                    output.ClusterLabels[clusterID],
                    output.ClusterDiameters[clusterID],
                    "cluster", clusterID);
                vertices.Add(v.VerticeID, v);
            }
            foreach(int fromClusterID in clusterClusterDistances.Keys)
            {
                Vertice fromVertice = vertices[fromClusterID];
                foreach(int toClusterID in clusterClusterDistances[fromClusterID].Keys)
                {
                    Vertice toVertice = vertices[toClusterID];
                    bool exist = false;
                    foreach(Edge edge in edges)
                    {
                        if(edge.FromVertice==fromVertice && edge.ToVertice==toVertice)
                        {
                            exist = true;
                            break;
                        }
                        if (edge.FromVertice == toVertice && edge.ToVertice == fromVertice)
                        {
                            exist = true;
                            break;
                        }
                    }
                    if(!exist)
                    {
                        Edge edge=new Edge(fromVertice, toVertice, clusterClusterDistances[fromClusterID][toClusterID], "");
                        edges.Add(edge);
                    }
                }
            }
        }

        private void GetNetworkBetweenDocument(DocumentClusteringOutput output, int clusterID,
            out Dictionary<int,Vertice> vertices, out List<Edge> edges)
        {
            vertices = new Dictionary<int, Vertice>();
            edges = new List<Edge>();
            Dictionary<int, Dictionary<int, double>> docDocDistances =
                new Dictionary<int, Dictionary<int, double>>();
            List<int> inclusedDocIDs = output.ClusteredDocs[clusterID].ToList();
            foreach (int docID1 in inclusedDocIDs)
            {
                Dictionary<int, double> toDocDistances = new Dictionary<int, double>();
                foreach (int docID2 in inclusedDocIDs)
                {
                    if (docID1 != docID2)
                    {
                        double distance = 1;
                        if (output.DocDocDistances.ContainsKey(docID1) &&
                            output.DocDocDistances[docID1].ContainsKey(docID2))
                            distance = output.DocDocDistances[docID1][docID2];
                        else if (output.DocDocDistances.ContainsKey(docID2) &&
                            output.DocDocDistances[docID2].ContainsKey(docID1))
                            distance = output.DocDocDistances[docID2][docID1];
                        toDocDistances.Add(docID2, distance);
                    }
                }
                docDocDistances.Add(docID1, toDocDistances);
            }

            foreach (int docID in inclusedDocIDs)
            {
                Vertice v = new Vertice(
                    docID,
                    "Doc " + docID.ToString(),
                    output.DocTitles[docID], 1.0,
                    "doc", docID);
                vertices.Add(v.VerticeID, v);
            }
            foreach (int fromDocID in docDocDistances.Keys)
            {
                Vertice fromVertice = vertices[fromDocID];
                foreach (int toDocID in docDocDistances[fromDocID].Keys)
                {
                    Vertice toVertice = vertices[toDocID];
                    bool exist = false;
                    foreach (Edge edge in edges)
                    {
                        if (edge.FromVertice == fromVertice && edge.ToVertice == toVertice)
                        {
                            exist = true;
                            break;
                        }
                        if (edge.FromVertice == toVertice && edge.ToVertice == fromVertice)
                        {
                            exist = true;
                            break;
                        }
                    }
                    if (!exist)
                    {
                        Edge edge = new Edge(fromVertice, toVertice, docDocDistances[fromDocID][toDocID], "");
                        edges.Add(edge);
                    }
                }
            }
        }
        #endregion

        private void rdGridView_Click(object sender, RoutedEventArgs e)
        {
            if(this.rdGridView.IsChecked.Value)
            {
                this.rdNetworkView.IsChecked = false;
                this.rdDendrogram.IsChecked = false;
                this.clusterGrid.Visibility = Visibility.Visible;
                this.clusterNetwork.Visibility = Visibility.Collapsed;
                this.clusterDendrogram.Visibility = Visibility.Collapsed;
            }
            else
            {
                this.clusterGrid.Visibility = Visibility.Collapsed;
            }
        }

        private void rdNetworkView_Click(object sender, RoutedEventArgs e)
        {
            if (this.rdNetworkView.IsChecked.Value)
            {
                this.rdGridView.IsChecked = false;
                this.rdDendrogram.IsChecked = false;
                this.clusterGrid.Visibility = Visibility.Collapsed;
                this.clusterNetwork.Visibility = Visibility.Visible;
                this.clusterDendrogram.Visibility = Visibility.Collapsed;
                this.clusterNetwork.StartSimulation();
            }
            else
            {
                this.clusterNetwork.Visibility = Visibility.Collapsed;
            }
        }

        private void rdDendrogram_Click(object sender, RoutedEventArgs e)
        {
            if(this.rdDendrogram.IsChecked.Value)
            {
                this.rdGridView.IsChecked = false;
                this.rdNetworkView.IsChecked = false;
                this.clusterDendrogram.Visibility = Visibility.Visible;
                this.clusterNetwork.Visibility = Visibility.Collapsed;
                this.clusterGrid.Visibility = Visibility.Collapsed;
            }
            else
            {
                this.clusterDendrogram.Visibility = Visibility.Collapsed;
            }
        }
    }
}
